package scmd

import (
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	once sync.Once
	tc   *Tmpcmds
)

type Tmpcmds struct {
	path string
	cmds *MCommands
}

func NewTempcmds(path string) *Tmpcmds {
	once.Do(func() {
		tc = &Tmpcmds{}
		tc.path = path
		tc.cmds = NewCommands(path)
	})
	return tc
}

func (tc *Tmpcmds) BatchLoad(cmds map[string]*MCommand) {
	tc.optimizeCmds(cmds)
	for _, cmd := range cmds {
		if !cmd.Done && cmd.File != nil {
			cmd.File.FileMask = strings.ReplaceAll(cmd.File.FileMask, "1", "0")
		}
	}
	tc.cmds.BatchLoad(cmds)
}

func (tc *Tmpcmds) Commands() map[string]*MCommand {
	return tc.cmds.GetBlocks()
}

func (tc *Tmpcmds) keysSortted(cmds map[string]*MCommand) []int {
	keys := make([]int, 0, len(cmds))
	for k := range cmds {
		key, _ := strconv.Atoi(k)
		keys = append(keys, key)
	}
	sort.Ints(keys)
	return keys
}

// 优化命令，将最后一次相同路径的命令设置为有效，其他的设置为已完成
func (tc *Tmpcmds) optimizeCmds(cmds map[string]*MCommand) (keys []int) {
	tmp := map[string]bool{}

	lenm := len(cmds)

	keys = tc.keysSortted(cmds)

	var key string
	for i := lenm - 1; i >= 0; i-- {
		key = strconv.Itoa(keys[i])

		if _, ok := tmp[cmds[key].Path]; !ok {
			tmp[cmds[key].Path] = true
			cmds[key].Done = false
			cmds[key].DoneTime = 0
		} else {
			cmds[key].Done = true
			cmds[key].DoneTime = time.Now().Unix()
		}
	}
	return
}

func (tc *Tmpcmds) UpdateFileMask(filepath string, blockIndex int, dim string) {
	cmds := tc.cmds.GetBlocks()
	for k, cmd := range cmds {
		if cmd.Path == filepath {
			cmd.File.FileMask = cmd.File.FileMask[:blockIndex] + dim + cmd.File.FileMask[blockIndex+1:]
			key, _ := strconv.Atoi(k)
			tc.cmds.Update(key, cmd)
		}
	}
}

func (tc *Tmpcmds) Lock() {
	tc.cmds.Lock()
}
func (tc *Tmpcmds) UnLock() {
	tc.cmds.Unlock()
}
func (tc *Tmpcmds) RLock() {
	tc.cmds.RLock()
}
func (tc *Tmpcmds) RUnLock() {
	tc.cmds.RUnlock()
}

func (tc *Tmpcmds) CheckFileBlock(filepath string, blockIndex int) int {
	tc.cmds.RLock()
	defer tc.cmds.RUnlock()

	cmds := tc.cmds.GetBlocks()
	for _, cmd := range cmds {
		if cmd.Path == filepath {
			if cmd.File.FileMask[blockIndex:blockIndex+1] == "1" {
				return 1
			} else {
				return 0
			}
		}
	}
	return -1
}

func (tc *Tmpcmds) GetLen() int {
	return tc.cmds.blocks.GetLen()
}

func (tc *Tmpcmds) Destroy() {
	tc.cmds.Destroy()
}

func (tc *Tmpcmds) Clean() {
	tc.cmds.Clean()
}
